home *** CD-ROM | disk | FTP | other *** search
/ Eagles Nest BBS 8 / Eagles_Nest_Mac_Collection_Disc_8.TOAST / Developer Tools⁄Additions / MacsbugBook / MacsBug Book Disk / Debugger Prefs sources / RD.p / RD.p
Encoding:
Text File  |  1990-11-14  |  10.6 KB  |  449 lines  |  [TEXT/MPS ]

  1. UNIT RD;
  2.  
  3. (* The following MPW commands will build the dcmd and copy it to the
  4.    "Debugger Prefs" file in the System folder. The dcmd's name in
  5.          MacsBug will be the name of the file built by the Linker.
  6.  
  7.         Pascal RD.p
  8.         Link dcmdGlue.a.o RD.p.o "{Libraries}Runtime.o" "{PLibraries}PasLib.o" -o RD
  9.         BuildDcmd RD 200
  10.         Echo 'include "RD";'    |    Rez -a -o "{systemFolder}Debugger Prefs"
  11. *)
  12.  
  13. {$R-}
  14.  
  15. INTERFACE
  16.  
  17.         USES MemTypes, dcmd;
  18.         
  19.   { Public declaration for dcmdGlue. Must be in every dcmd. The name cannot be changed. }
  20. PROCEDURE CommandEntry(paramBlk:DCmdBlockPtr);
  21.  
  22.  
  23. IMPLEMENTATION
  24.  
  25. PROCEDURE NumberToHex (number: LONGINT; VAR hex: Str255; len: INTEGER);
  26. VAR digits: Str255;
  27.     t: Str255;
  28.     n: INTEGER;
  29.      num: LONGINT;
  30. BEGIN
  31.         num := ABS(number);
  32.           digits := '0123456789ABCDEF';
  33.         hex := '';
  34.         t := '0';
  35.         FOR n := len DOWNTO 1 DO
  36.             BEGIN
  37.                 t[1] := digits[1 + (num MOD 16)];
  38.                 hex := Concat(t,hex);
  39.                 num := num DIV 16;
  40.             END;
  41.         IF number < 0 THEN hex := Concat('-',hex);
  42. END;
  43.  
  44. PROCEDURE NumberToDecimal (number: LONGINT; VAR decimal: Str255; len: INTEGER);
  45. VAR digits: Str255;
  46.     t: Str255;
  47.     n: INTEGER;
  48.      num: LONGINT;
  49.      signChar: Str15;
  50. BEGIN
  51.         IF number < 0 THEN
  52.             signChar := '-'
  53.         ELSE signChar := ' ';
  54.         num := ABS(number);
  55.           digits := '0123456789';
  56.         decimal := '';
  57.         t := '0';
  58.         FOR n := len DOWNTO 1 DO
  59.             BEGIN
  60.                 t[1] := digits[1 + (num MOD 10)];
  61.                 IF (num = 0) AND (n < len) THEN
  62.                     BEGIN
  63.                         decimal := Concat(signChar,decimal);
  64.                         signChar := ' ';
  65.                     END
  66.                 ELSE decimal := Concat(t,decimal);
  67.                 num := num DIV 10;
  68.             END;
  69. END;
  70.  
  71. { Fixed and Translated to Pascal by Jim Straus
  72.         from source translated to Modula-2 by Keith Nemitz
  73.         from source written by Julia Menapace. (8/88) }
  74.  
  75. TYPE
  76.     ResMap = RECORD
  77.                     dataOffset    :LongInt; { from BOF to resource data. }
  78.                     mapOfset        :LongInt; { from BOF to resource map. }
  79.                     dataLength    :LongInt;
  80.                     mapLength    :LongInt;
  81.                     
  82.                     nextMap        :Handle;
  83.                     fRefNum        :INTEGER;
  84.                     fAttrs        :INTEGER;
  85.                     typeListOffset :INTEGER; { from map to type list. }
  86.                     nameListOffset :INTEGER; { from map to name list. }
  87.                     END;
  88.     ResMapPtr = ^ResMap;
  89.     ResMapHnd = ^ResMapPtr;
  90.     
  91.     TypeList = RECORD
  92.                         count    :INTEGER; { number of elements minus 1 }
  93.                         list    :ARRAY [0..0] OF 
  94.                                     RECORD
  95.                                         rType    :ResType;
  96.                                         cnt    :INTEGER; { number of resources minus 1 }
  97.                                         offset:INTEGER; { from typelist to RefList }
  98.                                         END;
  99.                         END;
  100.     TypeListPtr = ^TypeList;
  101.     
  102.     rAttributes = (q0,q1,q2,q3,q4,q5,q6,q7,q8,
  103.                         changed,preload,protected,locked,purgable,sysAppHeap,{ 1 = sys, 0 = app }
  104.                         q15);
  105.     rAttrSet = SET OF rAttributes;
  106.     
  107.     RefList = ARRAY [0..0] OF
  108.                     RECORD
  109.                         idNum            :INTEGER;
  110.                         nameOffset    :INTEGER;    { from namelist to lenByte. -1 if no name. }
  111.                         CASE INTEGER OF
  112.                         1:    ( resAttrs    :rAttrSet;    { also the resOffset from resource data to length of resource }
  113.                             xresource        :Handle);
  114.                         2:    ( resOffset    :LongInt;    { fffset from resource data to length of resource }
  115.                             resource        :Handle);     { handle to resource }
  116.                     END;
  117.     RefListPtr = ^RefList;
  118.     
  119.     LongPtr    = ^LongInt;
  120.  
  121. VAR
  122.     ShowType :ResType;
  123.     FileNum,ResNum :INTEGER;
  124.     FileName :Str255;
  125.     allTypes,allNums,allFiles :BOOLEAN;
  126.  
  127. PROCEDURE DisplayHelp(s:Str255); FORWARD;
  128. FUNCTION ParseParameters:BOOLEAN; FORWARD;
  129. PROCEDURE GetFileName(fRefNum:LongInt; VAR t:Str255); FORWARD;
  130. FUNCTION StrCmp(s1,s2:Str255):BOOLEAN; FORWARD;
  131. PROCEDURE ResTypes(typList:TypeListPtr; names:StringPtr; VAR abort:BOOLEAN); FORWARD;
  132.  
  133. {Skips leading spaces on the command line}
  134. FUNCTION SkipSpace(ch: CHAR):CHAR;
  135. BEGIN
  136.     IF ch = ' ' THEN
  137.         BEGIN
  138.             ch := dcmdPeekAtNextChar;
  139.             WHILE ch = ' ' DO
  140.                 BEGIN
  141.                     ch := dcmdGetNextChar;
  142.                     ch := dcmdPeekAtNextChar;
  143.                 END;{while}
  144.         END;
  145.     SkipSpace := ch;
  146. END;
  147.  
  148. {Parses a file name or file refnum}
  149. FUNCTION ParseFileReq(ch:CHAR):BOOLEAN;
  150. VAR
  151.     n :LONGINT;
  152.     flag :BOOLEAN;
  153.     str :Str255;
  154. BEGIN
  155.     FileName := ''; FileNum := 0;
  156.     allFiles := FALSE;
  157.     ch := SkipSpace(ch);
  158.     IF (ch = '''') OR (ch = '"') THEN
  159.         BEGIN
  160.         ch := dcmdGetNextParameter(FileName);
  161.         ParseFileReq := TRUE;
  162.         END
  163.     ELSE BEGIN
  164.         ch := dcmdGetNextExpression(n,flag);
  165.         IF flag THEN
  166.             BEGIN
  167.             FileNum := n;
  168.             ParseFileReq := TRUE;
  169.             END
  170.         ELSE
  171.             BEGIN
  172.             DisplayHelp('Expected File Identifier');
  173.             ParseFileReq := FALSE;
  174.             END;
  175.     END;
  176. END;
  177.  
  178. FUNCTION ParseParameters:BOOLEAN;
  179. CONST CR = CHR(13);
  180. VAR
  181.     ch :CHAR;
  182.     n :LONGINT;
  183.     str :Str255;
  184.     flag :BOOLEAN;
  185. BEGIN
  186.     allTypes := TRUE; allNums := TRUE; allFiles := TRUE;
  187.     ShowType := '    ';
  188.     ch := ' ';
  189.     ch := SkipSpace(ch);
  190.     IF ch = CR THEN
  191.         ParseParameters := TRUE
  192.     ELSE IF ch = ',' THEN
  193.         BEGIN
  194.         ch := dcmdGetNextChar; { eat comma }
  195.         ParseParameters := ParseFileReq(' ');
  196.         END
  197.     ELSE
  198.         BEGIN    
  199.             allTypes := FALSE;
  200.             ch := dcmdGetNextParameter(str);
  201.             IF length(str) > 3 THEN
  202.                 BEGIN
  203.                     ShowType[1] := str[1];
  204.                     ShowType[2] := str[2];
  205.                     ShowType[3] := str[3];
  206.                     ShowType[4] := str[4];
  207.                 END;
  208.             ch := SkipSpace(ch);
  209.             IF ch = ',' THEN
  210.                 BEGIN
  211.                 ch := dcmdGetNextChar; { eat comma }
  212.                 ParseParameters := ParseFileReq(' ');
  213.                 END
  214.             ELSE IF ch = CR THEN
  215.                 ParseParameters := TRUE
  216.             ELSE BEGIN
  217.                 ch := dcmdGetNextExpression(n,flag);
  218.                 IF NOT flag THEN
  219.                     BEGIN
  220.                     DisplayHelp('Expected resource ID.');
  221.                     ParseParameters := FALSE
  222.                     END
  223.                 ELSE BEGIN
  224.                     allNums := FALSE;
  225.                     ResNum := n;
  226.                     
  227.                     ch := SkipSpace(ch);
  228.                     IF ch = CR THEN
  229.                         ParseParameters := TRUE
  230.                     ELSE
  231.                         ParseParameters := ParseFileReq(ch);
  232.                 END;
  233.             END;
  234.         END;
  235. END;
  236.  
  237. FUNCTION Upper(c: CHAR): CHAR;
  238. BEGIN
  239.     IF (c >= 'a') AND (c <= 'z')
  240.     THEN Upper := CHR(ORD(c)-ORD('a')+ORD('A'))
  241.     ELSE Upper := c;
  242. END;
  243.  
  244. FUNCTION StrCmp(s1,s2:Str255):BOOLEAN;
  245. VAR len,i :INTEGER;
  246. BEGIN
  247.     len := Length(s1);
  248.     IF len <> Length(s2) THEN StrCmp := FALSE
  249.     ELSE BEGIN
  250.         FOR i := 1 TO len DO
  251.             BEGIN
  252.             IF Upper(s1[i]) <> Upper(s2[i]) THEN BEGIN StrCmp := FALSE; EXIT(StrCmp); END;
  253.             END;
  254.         StrCmp := TRUE;
  255.     END;
  256. END;
  257.  
  258. PROCEDURE GetFileName(fRefNum:LongInt; VAR t:Str255);
  259. CONST
  260.     FCBSPtr    = $34E;     { low memory global to File Control Block Strings }
  261. VAR
  262.     myStrPtr :StringPtr;
  263. BEGIN  { Look up a file name in the File Control Block. }
  264.     myStrPtr := StringPtr(LongPtr(FCBSPtr)^ + (fRefNum+62));
  265.     t := myStrPtr^; { it's a pascal string in the FCB. }
  266. END;
  267.  
  268.     { show the list of attributes for a particular resource. Uppercase means active. }
  269. PROCEDURE ShowBits(VAR s:Str255; attrs:rAttrSet);
  270. VAR ch :Str255;
  271. BEGIN
  272.     IF changed IN attrs THEN
  273.         ch := 'C'
  274.     ELSE
  275.         ch := 'c';
  276.     s := Concat(s,ch);
  277.     IF preload IN attrs THEN
  278.         ch := 'D'
  279.     ELSE
  280.         ch := 'd';
  281.     s := Concat(s,ch);
  282.     IF protected IN attrs THEN
  283.         ch := 'T'
  284.     ELSE
  285.         ch := 't';
  286.     s := Concat(s,ch);
  287.     IF locked IN attrs THEN
  288.         ch := 'L'
  289.     ELSE
  290.         ch := 'l';
  291.     s := Concat(s,ch);
  292.     IF purgable IN attrs THEN
  293.         ch := 'P'
  294.     ELSE
  295.         ch := 'p';
  296.     s := Concat(s,ch);
  297.     IF sysAppHeap IN attrs THEN
  298.         ch := 'S'
  299.     ELSE
  300.         ch := 'A';
  301.     s := Concat(s,ch);
  302. END;
  303.  
  304. PROCEDURE ShowName(VAR s:Str255; name:StringPtr); { build the resource name. }
  305. VAR t :Str255;
  306. BEGIN
  307.     s := Concat(s,'   Name: ');
  308.     t := name^; { it's a pascal string in the resource name list. }
  309.     s := Concat(s,t);
  310. END;
  311.  
  312. FUNCTION StripAddr(n: Handle): LONGINT;
  313. CONST
  314.     MaskHandle = $31a;
  315. BEGIN
  316.     StripAddr := BAnd(LongInt(n),LongPtr(MaskHandle)^);
  317. END;
  318.  
  319. PROCEDURE ResInfo(rList:RefListPtr; count:INTEGER; names:StringPtr);
  320. VAR
  321.     i :INTEGER;
  322.     sPtr :StringPtr;
  323.     s,t :Str255;
  324. BEGIN
  325.     FOR i := 0 TO count DO { show info for all resources of this type }
  326.         WITH rList^[i] DO
  327.             BEGIN
  328.                 IF allNums OR (ResNum = idNum) THEN
  329.                     BEGIN
  330.                         NumberToDecimal(idNum,t,6);
  331.                         s := Concat('  ID: ',t);
  332.                         s := Concat(s,'   at: ');
  333.                         IF resource = NIL THEN { for loaded resources show the Master Pointer address }
  334.                             t := 'Unloaded'
  335.                         ELSE
  336.                             NumberToHex(StripAddr(resource),t,8);
  337.  
  338.                         s := Concat(s,t);
  339.                         IF LongInt(resource) < 0 THEN { Is the Locked bit set? }
  340.                             s := Concat(s,' *  Attribs: ') { Yes. }
  341.                         ELSE
  342.                             s := Concat(s,'    Attribs: '); { No. }
  343.  
  344.                         ShowBits(s,resAttrs); { show the resource attributes. }
  345.                         IF nameOffset <> -1 THEN
  346.                             BEGIN
  347.                             sPtr := StringPtr(LONGINT(names) + LONGINT(nameOffset));
  348.                             ShowName(s,sPtr); { show the resource name, if one. }
  349.                             END;
  350.                         dcmdDrawLine(s);
  351.                     END;
  352.             END;
  353. END;
  354.  
  355. PROCEDURE ResTypes(typList:TypeListPtr; names:StringPtr; VAR abort:BOOLEAN);
  356. VAR
  357.     i :INTEGER;
  358.     rListPtr :RefListPtr;
  359.     s,t :Str255;
  360. BEGIN
  361.     WITH typList^ DO
  362.         BEGIN
  363.         {
  364.         IntToStr(count+1,t,4);
  365.         Concat(' Number of Resource types: ',t,s);
  366.         dcmdDrawLine(s);
  367.         }
  368.         FOR i := 0 TO count DO { loop through every type of resource. }
  369.             BEGIN
  370.             IF abort THEN Exit(ResTypes);
  371.             WITH list[i] DO
  372.                 IF allTypes OR (LONGINT(ShowType)=LONGINT(rType)) THEN
  373.                     BEGIN
  374.                     t := '    ';
  375.                     t[1] := rType[1];
  376.                     t[2] := rType[2];
  377.                     t[3] := rType[3];
  378.                     t[4] := rType[4];
  379.                     s := Concat(' type: ',t);
  380.                     s := Concat(s,'  Instances: ');
  381.                     NumberToDecimal(cnt+1,t,4);
  382.                     s := Concat(s,t);
  383.                     dcmdDrawLine(s);
  384.                     rListPtr := RefListPtr(LONGINT(typList) + LONGINT(offset));
  385.                     ResInfo(rListPtr,cnt,names);
  386.                     END;
  387.             END;
  388.         END;
  389. END;
  390.  
  391. PROCEDURE DisplayHelp(s:Str255);
  392. BEGIN
  393.     dcmdDrawLine(s);
  394.     dcmdDrawLine('RD [resType[ resNum]] [,"fileName"|fileNum]');
  395.     dcmdDrawLine('   Displays the specified resources and resource files.');
  396. END;
  397.  
  398. PROCEDURE CommandEntry(paramBlk:DCmdBlockPtr);
  399. CONST
  400.     TopMapHndl    = $A50;    {ResMapHnd - low memory global to the first map in the map list. }
  401. VAR
  402.     fileRef :INTEGER;
  403.     tlPtr :TypeListPtr;
  404.     namesPtr :StringPtr;
  405.     NextResFile :ResMapHnd;
  406.     s,t :Str255;
  407. BEGIN
  408.     IF paramBlk^.request = dcmdHelp THEN
  409.         BEGIN
  410.             DisplayHelp('');
  411.             Exit(CommandEntry);
  412.         END
  413.     ELSE IF paramBlk^.request = dcmdInit THEN
  414.         BEGIN
  415.             Exit(CommandEntry);
  416.         END;
  417.     { Get the command paramters }
  418.     IF NOT ParseParameters THEN Exit(CommandEntry);
  419.         
  420.     NextResFile := ResMapHnd(ResMapHnd(TopMapHndl)^);
  421.     dcmdDrawLine('Resource Chain - Top to bottom:');
  422.     REPEAT { loop through all resource files. }
  423.         fileRef := NextResFile^^.fRefNum;
  424.         
  425.         NumberToHex(LongInt(NextResFile^),t,8);
  426.         s := Concat('Map at: ',t);
  427.         s := Concat(s,'  File RefNum: $');
  428.         NumberToHex(fileRef,t,6);
  429.         s := Concat(s,t);
  430.  
  431.         GetFileName(fileRef,t);
  432.         s := Concat(s,'  File Name: ');
  433.         s := Concat(s,t);
  434.         dcmdDrawLine(s);
  435.         IF allFiles OR (FileNum = fileRef) OR StrCmp(FileName,t) THEN
  436.             BEGIN
  437.             { find pointers to the type list and the resource name list. }
  438.             tlPtr := TypeListPtr(LONGINT(NextResFile^) +
  439.                             LONGINT(NextResFile^^.typeListOffset));
  440.             namesPtr := StringPtr(LONGINT(NextResFile^) +
  441.                             LONGINT(NextResFile^^.nameListOffset));
  442.             ResTypes(tlPtr,namesPtr,paramBlk^.aborted);
  443.             END;
  444.         IF paramBlk^.aborted THEN Exit(CommandEntry);
  445.         NextResFile := ResMapHnd(NextResFile^^.nextMap);
  446.         UNTIL NextResFile = NIL; { null terminated list. }
  447. END;
  448. END.
  449.